home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc Source Code / Storage / Clipbd.cpp next >
Encoding:
Text File  |  1996-04-22  |  63.8 KB  |  2,106 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Clipbd.cpp
  3.  
  4.     Contains:    Implementation for ODClipboard class.
  5.  
  6.     Owned by:    Craig Carper
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <3>     3/29/96    DM        1296171: suppress fatal Bento container
  13.                                     errors in all clipboard methods
  14.          <2>     3/26/96    CC        1333462: CloseClipboard: ClearAllPromises
  15.                                     if not externalizing the clipboard draft.
  16.         <54>     10/9/95    CC        1289794: Avoid calling GetScrap if scrap is
  17.                                     in an inconsistent state.
  18.                                     1288241: SetPlatformClipboard prevents
  19.                                     exporting clipboard.
  20.                                     1290782: Purge is not implemented.
  21.                                     1286400: Preflight scrap memory
  22.                                     allocations.
  23.         <53>     10/3/95    TJ        Changes done by RefBall Team
  24.         <52>     9/26/95    EL        1285709: ODClipboard does not close down
  25.                                     properly if it was never accessed.
  26.         <51>      9/8/95    TÇ        1281096 FB2:Many constants in ODTypesB
  27.                                     without kOD prefix!
  28.         <50>     8/31/95    DM        1273863, 1275336: add ODClipboard::
  29.                                     DraftSaved(), make GetOriginalDraft() honor
  30.                                     standard endianess
  31.         <49>     8/30/95    EL        1279832: Storage THROW_IF_NULL problems.
  32.         <48>     8/29/95    DM        1276549: call parent Purge in ODClipboard
  33.         <47>     8/26/95    TÇ        1274606 FB2: Patching Remarks
  34.         <46>     8/25/95    CC        1264154: Added ActionDone, ActionUndone,
  35.                                     and ActionRedone methods.
  36.         <45>     8/21/95    VL        1277291: Use GetOriginalCloneKind from
  37.                                     StorUtil.
  38.         <44>     8/16/95    NP        1274946: ErrorDef.idl problems. Add include
  39.                                     file.
  40.         <43>     8/12/95    TÇ        1276812 Need to use TempObjs and TempRefs
  41.                                     for exception safety and to avoid TRY
  42.                                     blocks, 1276807 Opt./Bug: use StdTypIO
  43.                                     routines for portable streaming & smaller
  44.                                     footprint
  45.         <42>      8/3/95    RR        #1257260: Collapse B classes. Remove
  46.                                     somInit methods. Don't call IsInitialized
  47.                                     or SubclassResponsibility
  48.         <41>     7/26/95    DM        #1270320: Memory leak fixes: dispose handle
  49.                                     on return in ODClipboardImportContent
  50.         <40>     7/20/95    CC        1153954: ExportPlatformTypes: Don't move
  51.                                     types to scrap that are not platform types.
  52.                                     1260342: Clear: fail if process is in the
  53.                                     background.
  54.         <39>      7/1/95    CC        1264197: DraftClosing must not remove
  55.                                     Original Draft property.  Instead, change
  56.                                     original clone kind to kODCloneCopy.
  57.                                     1257374: Added ForceZeroScrap(), called
  58.                                     from SetPlatformClipboard() and
  59.                                     ExportClipboard() methods.
  60.         <38>     6/23/95    CC        1260902: ImportContent: Skip if scrap
  61.                                     handle is null, and Ignore types of size
  62.                                     zero.
  63.                                     1257374: GetContentStorageUnit: Never issue
  64.                                     debugger break on failure to import from
  65.                                     the system scrap.
  66.         <37>     6/19/95    CC        1259079: Added local function
  67.                                     IsFrontProcess.
  68.                                     GetContentStorageUnit: Don't warn if
  69.                                     process is in background.
  70.         <36>     5/26/95    VL        1251403: Multithreading naming support.
  71.         <35>     5/22/95    CC        1251106: CloseClipboard externalizes root
  72.                                     SU to resolve promises before externalizing
  73.                                     the clipboard draft.
  74.         <34>     5/18/95    CC        1250280: ShowPasteAsDialog throws on
  75.                                     invalid null arguments.
  76.         <33>     5/17/95    RR        #1250135/1250137/1250143 Getters increment
  77.                                     refcount
  78.         <32>     5/16/95    CC        1244991: ExportClipboard: Re-export
  79.                                     clipboard if link spec has been removed.
  80.                                     ExportClipboard: Set fOriginalDraft field.
  81.                                     DiscardClipboard: Added SOM_CATCH return.
  82.         <31>      5/5/95    CC        1224474: ImportContent: Fixed memory leak
  83.                                     due to variable theISOType
  84.         <30>     4/25/95    CC        1242555: PutContentOnPlatformClipboard:
  85.                                     Removed obsolete $5 comment.
  86.         <29>     4/14/95    TÇ        #1235279 BB: InfoUtil & StdTypIO functions
  87.                                     should take Environment* and SU* when
  88.                                     possible
  89.         <28>     4/11/95    CC        1231378: DraftClosing: Removed link spec if
  90.                                     present.
  91.         <27>     3/22/95    CC        1230322: Changed parameter to
  92.                                     ShowPasteAsDialog().
  93.         <26>     3/10/95    CC        1225050: Added DraftClosing() method.
  94.                                     1227468: Clear: Set fScrapCount to ensure a
  95.                                     changed clipboard is exported again.
  96.         <25>     2/24/95    CC        1222076: BB: Clipboard contents lost on
  97.                                     error converting to Mac scrap.
  98.                                     1184034:    BB: Error -108 during
  99.                                     cross-document paste link.
  100.                                     1186774, 1201430, 1218790:    Ignore GetScrap
  101.                                     errors.
  102.                                     1223020:    ODClipboard calls LoadScrap() at
  103.                                     innapropriate times.
  104.                                     Fixed mismatched delimiters: #include
  105.                                     <ODDebug.h".
  106.         <24>     2/14/95    jpa        Added return statement to a SOM_CATCH
  107.                                     [1215160]
  108.         <23>     2/10/95    CG        #1177475: Added include for StdDefs.xh.
  109.         <22>      2/7/95    CC        1211295: Added GetOriginalCloneKind().
  110.                                     Pass isMove parameter to ShowPasteAsDialog.
  111.                                     1216124: ShowPasteAsDialog aquires modal
  112.                                     focus.
  113.         <21>      2/1/95    CC        1153802: Improvements to
  114.                                     ImportStyledTextType().
  115.                                     ImportContent(): Create stxt only if not
  116.                                     already present.
  117.         <20>     1/26/95    VL        #???: Use updated Storage Unit Ref API.
  118.         <19>     1/25/95    CC        1153802 Conversion between 'styl' and
  119.                                     'stxt' types: Added ImportStyledTextType
  120.                                     and ExportStylType functions.
  121.         <18>     1/19/95    CC        1212419 Add parameter to
  122.                                     GetMemoryContainer.
  123.                                     1212833 Change to use
  124.                                     kODScrapTypeODBentoContainer.
  125.         <17>    12/20/94    VL        1195012: Make Storage calls be
  126.                                     marshallable.
  127.         <16>     12/8/94    CC        1186774, 1201430 - Suppress errors returned
  128.                                     when reading the scrap.
  129.         <15>     9/29/94    RA        1189812: Mods for 68K build.
  130.         <14>     9/23/94    VL        1155579, 1184272: Use StorUtil to
  131.                                     create/get container and get its file.
  132.         <13>     9/19/94    CC        1187315 - somUninit() must call parent
  133.                                     method last.
  134.                                     1160121 - Clear() must not return an error.
  135.         <12>     9/15/94    CC        1186774 - Suppress GetScrap() errors.
  136.         <11>     8/26/94    VL        1183174: Use updated cloning APIs.
  137.         <10>     8/15/94    TÇ        #1180922 Removed most obsolete types from
  138.                                     StdTypes.idl
  139.          <9>      8/3/94    CC        Removed Lock() and Unlock(); removed
  140.                                     ODClipboardKey parameter from other
  141.                                     methods.  (1160484)
  142.          <8>      8/3/94    VL        1153123: Storage to ODStor.
  143.          <7>      8/2/94    CC        #1178169 - ShowPasteAsDialog() takes
  144.                                     ODFacet* instead of ODFrame*.
  145.          <6>     7/31/94    CC        Change WASSERTs to WARNs.
  146.          <5>     7/12/94    CC        Companion to .idl checkin -- no changes.
  147.          <4>     6/28/94    VL        Used Translt.xh.
  148.          <3>     6/24/94    CC        Use kODScrapTypePart constant in
  149.                                     ConstDef.h.
  150.          <2>     6/24/94    CC        Fleshed out ShowPasteAsDialog().
  151.          <1>     6/21/94    CC        first checked in
  152.  
  153.         ------------------- CC ---- Converted to SOM
  154.  
  155.         <13>      5/9/94    MB        Changes necessary to install MMM. Bug
  156.                                     #1162181.
  157.         <12>      4/4/94    CC        SetPlatformClipboard() &
  158.                                     ExportPlatformClipboard(): Parameter
  159.                                     changed from XMPTypeSet to XMPTypeList
  160.                                     (1153046)
  161.         <11>     3/28/94    CG        1153547: Renamed XMPSessn.h to XMPSessM.h
  162.         <10>     3/27/94    TÇ        #1153523.  Adjust name of
  163.                                     kXMPPropRootPartSU to more clearly indicate
  164.                                     what it is supposed to be used for.
  165.          <9>     3/25/94    JA        Added missing #include (1147588)
  166.          <8>     3/18/94    CC        Added counting locks to Lock() and
  167.                                     Unlock(); Implementation of and calls to
  168.                                     ValidateKey(). (1151853)
  169.          <7>     3/16/94    CG        #1151186: Added call to InitPlatformTypeSet
  170.                                     after new XMPPlatformTypeSet.
  171.          <6>      3/2/94    CC        Lock() & Unlock(): Commented out erroneous
  172.                                     WASSERTs. (1145487)
  173.          <5>     2/28/94    VL        Changed code that may cause memory
  174.                                     problems.
  175.          <4>     2/22/94    VL        THROW -> THROW_IF_ERROR.
  176.          <3>     2/15/94    CC        Bug #1142933 - Added key parameter to
  177.                                     SetPlatformClipboard.
  178.          <2>     2/15/94    CC        Bug #1142949 - Adapted to method name
  179.                                     changes in XMPPlatformTypeSet.
  180.          <3>      2/8/94    VL        Use new exception macros.
  181.          <2>      2/4/94    VL        Session.h -> XMPSessn.h.
  182.          <1>      2/4/94    VL        first checked in
  183.  
  184.         <21>      2/4/94    VL        Moved to PPC Header and began code cleanup.
  185.         <20>     1/28/94    CC        Implemented change ids; replaced DebugStrs
  186.                                     with WASSERTMs.
  187.         <19>     1/21/94    CC        Converted from XMPTimeStamp to XMPUpdateID.
  188.                                     Added GetUpdateID.  GetLock() returns
  189.                                     boolean result and returns key in second
  190.                                     parameter.
  191.         <18>     1/21/94    CG        Renamed kXMPMemoryContainer to
  192.                                     kXMPDefaultMemoryContainer.
  193.         <17>     1/18/94    CG        Added include for StorgDef.yh
  194.         <16>     1/18/94    CC        Use kXMPScrapTypePart; release draft
  195.                                     properties on failure in NewClipboard() and
  196.                                     ImportClipboard().
  197.         <15>     1/14/94    CC        Added type XMPClipboardKey, added key
  198.                                     parameter to various routines, replaced
  199.                                     GetGeneration() with GetTimeStamp, renamed
  200.                                     AcquireStorageUnit() GetContentStorageUnit();
  201.                                     changed from using a handle to a pointer in
  202.                                     ExportPlatformTypes() and
  203.                                     PutContentOnPlatformClipboard().
  204.         <14>     1/11/94    TÇ        Init... changes
  205.         <13>    12/21/93    VL        Changed XMPStorageUnit::GetValueSize to
  206.                                     StorageUnit::GetSize.
  207.         <12>    12/15/93    TÇ        more InitObject changes, remove
  208.                                     Initialize() method
  209.         <11>    12/15/93    TÇ        InitObject changes
  210.         <10>     12/2/93    CC        Added Lock(), Unlock(), and GetGeneration()
  211.                                     methods.
  212.          <9>    11/10/93    CC        Doesn't externalize draft before disposing
  213.                                     memory container
  214.          <8>     11/1/93    VL        Used Strong reference.
  215.          <7>    10/29/93    RR        XMPClipboard:: -> XMPMacClipboard
  216.          <6>    10/27/93    CC        Added methods to transfer to/from the
  217.                                     platform clipboard.
  218.          <5>    10/20/93    CC        Added session parameter to XMPClipboard
  219.                                     constructor; added SetPlatformClipboard
  220.                                     method; added code to create the clipboard
  221.                                     container.
  222.          <3>     4/29/93    VL        More 8.3 Name Change.
  223.          <2>     4/29/93    VL        8.3 Name Change.
  224.          <1>     4/27/93    VL        first checked in
  225.  
  226.     To Do:
  227.     • Reuse fContainerHandle when possible after exporting it.
  228.     • Add a resolvePromises parameter to ExportClipboard (but maybe we need to
  229.         do this all the time).
  230.     • Vincent will add a draft change seed.  The clipboard object can examine
  231.         the seed for the clipboard draft to determine if the clipboard has
  232.         been changed since it was exported (if the clipboard generation is the
  233.         same).
  234.     • XMPClipboard::Clear() should clear the system clipboard.
  235.     
  236.     In Progress:
  237.         
  238. */
  239.  
  240. #define VARIABLE_MACROS
  241.  
  242. #define ODClipboard_Class_Source
  243. #include <Clipbd.xih>
  244.  
  245. #ifndef SOM_Module_OpenDoc_StdDefs_defined
  246. #include <StdDefs.xh>
  247. #endif
  248.  
  249. #ifndef _EXCEPT_
  250. #include <Except.h>
  251. #endif
  252.  
  253. #ifndef _ODMEMORY_
  254. #include <ODMemory.h>
  255. #endif
  256.  
  257. #ifndef _CONSTDEF_
  258. #include <ConstDef.h>
  259. #endif
  260.  
  261. #ifndef _PLFMDEF_
  262. #include <PlfmDef.h>
  263. #endif
  264.  
  265. #ifndef _ISOSTR_
  266. #include <ISOStr.h>
  267. #endif
  268.  
  269. #ifndef _ODUTILS_
  270. #include <ODUtils.h>
  271. #endif
  272.  
  273. #ifndef SOM_Module_OpenDoc_StdProps_defined
  274. #include <StdProps.xh>
  275. #endif
  276.  
  277. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  278. #include <StdTypes.xh>
  279. #endif
  280.  
  281. #ifndef SOM_Module_OpenDoc_Foci_defined
  282. #include <Foci.xh>
  283. #endif
  284.  
  285. #ifndef SOM_ODSession_xh
  286. #include <ODSessn.xh>
  287. #endif
  288.  
  289. #ifndef SOM_ODArbitrator_xh
  290. #include <Arbitrat.xh>
  291. #endif
  292.  
  293. #ifndef SOM_ODContainer_xh
  294. #include <ODCtr.xh>
  295. #endif
  296.  
  297. #ifndef SOM_ODDocument_xh
  298. #include <Document.xh>
  299. #endif
  300.  
  301. #ifndef SOM_ODDraft_xh
  302. #include <Draft.xh>
  303. #endif
  304.  
  305. #ifndef SOM_ODStorageSystem_xh
  306. #include <ODStor.xh>
  307. #endif
  308.  
  309. #ifndef SOM_ODStorageUnit_xh
  310. #include <StorageU.xh>
  311. #endif
  312.  
  313. #ifndef SOM_ODTranslation_xh
  314. #include <Translt.xh>
  315. #endif
  316.  
  317. #ifndef SOM_ODTypeList_xh
  318. #include <TypeList.xh>
  319. #endif
  320.  
  321. #ifndef SOM_ODPlatformTypeList_xh
  322. #include <PfTypLs.xh>
  323. #endif
  324.  
  325. #ifndef _LINKDLGS_
  326. #include <LinkDlgs.h>
  327. #endif
  328.  
  329. #ifndef __SCRAP__
  330. #include <Scrap.h>
  331. #endif
  332.  
  333. #ifndef _ODDEBUG_
  334. #include <ODDebug.h>
  335. #endif
  336.  
  337. #ifndef __ERRORS__
  338. #include <Errors.h>
  339. #endif
  340.  
  341. #ifndef _STDTYPIO_
  342. #include <StdTypIO.h>
  343. #endif
  344.  
  345. #ifndef _TEMPOBJ_
  346. #include <TempObj.h>
  347. #endif
  348.  
  349. #ifndef _STORUTIL_
  350. #include <StorUtil.h>
  351. #endif
  352.  
  353. #ifndef _UTILERRS_
  354. #include "UtilErrs.h"
  355. #endif
  356.  
  357. #ifndef __TEXTEDIT__
  358. #include <TextEdit.h>    // for ScrpSTElement
  359. #endif
  360.  
  361. #pragma segment ODClipboard
  362.  
  363. #include "ClipbdB.cpp"    // Platform-independent methods, if any
  364.  
  365. #if ODDebug
  366. #define ODDebugClipboard 0
  367. #undef _REPORT_SCRAP_ERRORS_
  368. #else
  369. #define ODDebugClipboard 0
  370. #undef _REPORT_SCRAP_ERRORS_
  371. #endif
  372.  
  373. //==============================================================================
  374. // Constants
  375. //==============================================================================
  376.  
  377. const short kInvalidScrapCount = -1;    // Must never match the scrap count!
  378.  
  379. // Mac Scrap state constants
  380. const short kUninitializedScrap = -1;
  381. const short kScrapOnDisk = 0;
  382.  
  383. //==============================================================================
  384. // Function Prototypes
  385. //==============================================================================
  386.  
  387. ODStatic ODULong ApplicationHeapFree();
  388. ODStatic short GetMacScrapCount();
  389. ODStatic ODBoolean IsFrontProcess();
  390. ODStatic void ImportStyledTextType(ODClipboard *somSelf, Environment *ev);
  391. ODStatic OSErr ExportStylType(ODPtr    stxtData);
  392. ODStatic void CloseClipboard(ODClipboard *somSelf, Environment *ev, ODBoolean externalize);
  393. ODStatic void OpenClipboard(ODClipboard *somSelf, Environment *ev);
  394. ODStatic ODBoolean ScrapIsInconsistent();
  395. ODStatic ODBoolean ScrapHasData();
  396. ODStatic ODBoolean ScrapHasType(ODPlatformType type);
  397. ODStatic OSErr ForceZeroScrap();
  398. ODStatic ODBoolean ScrapMemoryAvailable(Size dataSize);
  399. ODStatic OSErr UnloadScrapIfMemLow(Size dataSize);
  400. ODStatic OSErr ClipboardLoadScrap();
  401. ODStatic OSErr ClipboardPutScrap(Size dataSize, ODPlatformType    platformType, ODPtr data);
  402.  
  403. //==============================================================================
  404. // Utility Functions
  405. //==============================================================================
  406.  
  407. //------------------------------------------------------------------------------
  408. // SetOriginalCloneKind
  409. //------------------------------------------------------------------------------
  410.  
  411. static void SetOriginalCloneKind(Environment* ev, ODDraft* draft, ODCloneKind cloneKind)
  412. {
  413.     if ( draft != kODNULL )
  414.     {
  415.         TempODStorageUnit draftProperties = draft->AcquireDraftProperties(ev);
  416.         ODSetULongProp(ev, draftProperties, kODPropOriginalCloneKind, kODULong, (ODULong)cloneKind);
  417.     }
  418. }
  419.  
  420. //------------------------------------------------------------------------------
  421. // GetOriginalDraft
  422. //------------------------------------------------------------------------------
  423. // Returns kODNULL if the original draft is unknown.  This is the case when content
  424. // was placed in the draft without cloning.
  425.  
  426. static ODDraft* GetOriginalDraft(Environment* ev, ODDraft* draft)
  427. {
  428.     TempODStorageUnit    draftProperties = draft->AcquireDraftProperties(ev);
  429.     return (ODDraft*)ODGetULongProp(ev, draftProperties, kODPropOriginalDraft, kODULong);
  430. }
  431.  
  432. //==============================================================================
  433. // ODClipboard
  434. //==============================================================================
  435.  
  436. extern ODBoolean gODSuppressBentoFatalError; // defined in SessHdr.cpp
  437.  
  438. //------------------------------------------------------------------------------
  439. // ODClipboard::somUninit
  440. //------------------------------------------------------------------------------
  441.  
  442. SOM_Scope void  SOMLINK ODClipboardsomUninit(ODClipboard *somSelf)
  443. {
  444.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  445.     ODClipboardMethodDebug("ODClipboard","somUninit");
  446.     
  447.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  448.     gODSuppressBentoFatalError = kODTrue;
  449.     
  450.     Environment *ev = somGetGlobalEnvironment();
  451.     // somSelf->DiscardClipboard(ev); 
  452.     // It is incorrect to call methods on somSelf inside somUninit, 
  453.     // a subclass may have already been somUninited.  See OpenDoc Building Code for details.
  454.     // Instead the implementation of DiscardClipboard has been copied here.
  455.     
  456.     // BEGIN copy of DiscardClipboard implementation
  457.     CloseClipboard(somSelf, ev, kODFalse);
  458.     
  459.     ODDisposeHandle(_fContainerHandle);
  460.     _fContainerHandle = (ODHandle) kODNULL;
  461.     // END copy of DiscardClipboard implementation
  462.  
  463.     parent_somUninit(somSelf);
  464.     
  465.     gODSuppressBentoFatalError = oldSuppress; // neutral
  466. }
  467.  
  468. //------------------------------------------------------------------------------
  469. // ODClipboard::InitClipboard
  470. //------------------------------------------------------------------------------
  471.  
  472. SOM_Scope void  SOMLINK ODClipboardInitClipboard(ODClipboard *somSelf, Environment *ev,
  473.         ODSession* session)
  474. {
  475.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  476.     ODClipboardMethodDebug("ODClipboard","InitClipboard");
  477.  
  478.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  479.     gODSuppressBentoFatalError = kODTrue;
  480.  
  481.     /* Moved from somInit. SOM itself sets fields to zero
  482.     _fSession            = (ODSession*) kODNULL;
  483.     _fContainerHandle    = (ODHandle) kODNULL;
  484.     _fContainer            = (ODContainer*) kODNULL;
  485.     _fDocument            = (ODDocument*) kODNULL;
  486.     _fDraft                = (ODDraft*) kODNULL;
  487.     _fSU                = (ODStorageUnit*) kODNULL;
  488.     
  489.     _fOriginalDraft        = (ODDraft*) kODNULL;
  490.     _fExportedLinkSpec    = kODFalse;
  491.  
  492.     _fClonePasteCount    = 0;
  493.     */
  494.     somSelf->InitObject(ev);
  495.             
  496.     _fSession = session;
  497.  
  498.     // Initialize our scrap count to an invalid value so a paste will force copying
  499.     // from the platform scrap.
  500.     _fScrapCount            = kInvalidScrapCount;
  501.     _fScrapCountLastChange    = kInvalidScrapCount;
  502.     
  503.     _fUpdateID = kODUnknownUpdate;
  504.     _fNextUpdateID = _fSession->UniqueUpdateID(ev);
  505.  
  506.     _fOriginalCloneKind = kODCloneCopy;
  507.     
  508.     gODSuppressBentoFatalError = oldSuppress; // neutral
  509. }
  510.  
  511. //------------------------------------------------------------------------------
  512. // ApplicationHeapFree
  513. //------------------------------------------------------------------------------
  514.  
  515. ODStatic ODULong ApplicationHeapFree()
  516. {
  517.     ODULong free;
  518.     THz curZone = GetZone();
  519.     SetZone(ApplicationZone());
  520.     free = FreeMem();
  521.     SetZone(curZone);
  522.     return free;
  523. }
  524.  
  525. //------------------------------------------------------------------------------
  526. // ODClipboard::Purge (OVERRIDE)
  527. //------------------------------------------------------------------------------
  528.  
  529. SOM_Scope ODSize  SOMLINK ODClipboardPurge(ODClipboard *somSelf, Environment *ev,
  530.     ODSize size)
  531. {
  532.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  533.     ODClipboardMethodDebug("ODClipboard","Purge");
  534.     
  535.     ODSize freed = 0;
  536.     ODVolatile(freed);
  537.             
  538.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  539.     gODSuppressBentoFatalError = kODTrue;
  540.             
  541.     SOM_TRY
  542.  
  543.         Size scrapSize = InfoScrap()->scrapSize;
  544.         short scrapCount = GetMacScrapCount();
  545.         
  546.         if ( InfoScrap()->scrapState > kScrapOnDisk )
  547.         {
  548.             freed += scrapSize;
  549.             if ( (scrapCount == _fScrapCountLastChange) && (scrapCount == _fScrapCount) )
  550.             {
  551.                 ForceZeroScrap();
  552.                 // Update scrap later
  553.                 _fScrapCountLastChange = _fScrapCount = GetMacScrapCount();
  554.  
  555.                 #if ODDebugClipboard
  556.                     PRINT("ODClipboard::Purge: Scrap cleared\n");
  557.                 #endif
  558.             }
  559.             else
  560.             {
  561.                 UnloadScrap();
  562.  
  563.                 #if ODDebugClipboard
  564.                     if ( InfoScrap()->scrapState > kScrapOnDisk )
  565.                         PRINT("ODClipboard::Purge: Scrap unloaded\n");
  566.                 #endif
  567.             }
  568.             #if ODDebugClipboard
  569.                 PRINT("ODClipboard::Purge: Freed %ld bytes in app heap\n", freed);
  570.             #endif
  571.         }    
  572.  
  573.         freed += parent_Purge(somSelf, ev, size); // always call parent version of Purge()
  574.  
  575.     SOM_CATCH_ALL
  576.         WARN("Error %ld trying to purge in ODClipboardPurge",ErrorCode());
  577.         SetErrorCode(kODNoError);        // Eat the exception; Purge should not 
  578.                                         // propagate it because clients function
  579.                                         // fine whether memory was purged or not.
  580.     SOM_ENDTRY
  581.  
  582.     gODSuppressBentoFatalError = oldSuppress; // neutral
  583.  
  584.     return freed;
  585. }
  586.  
  587. //------------------------------------------------------------------------------
  588. // ODClipboard::NewClipboard
  589. //------------------------------------------------------------------------------
  590.  
  591. SOM_Scope void  SOMLINK ODClipboardNewClipboard(ODClipboard *somSelf, Environment *ev)
  592. {
  593.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  594.     ODClipboardMethodDebug("ODClipboard","NewClipboard");
  595.  
  596.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  597.     gODSuppressBentoFatalError = kODTrue;
  598.  
  599.     SOM_CATCH
  600.     {
  601.         gODSuppressBentoFatalError = oldSuppress; // neutral
  602.         return;
  603.     }
  604.  
  605.     ODStorageUnit* draftProperties = (ODStorageUnit*) kODNULL;
  606.     
  607.     ODVolatile(draftProperties);
  608.     ODVolatile(somSelf);
  609.     ODVolatile(ev);
  610.  
  611.     TRY
  612.         // Create a new clipboard in-memory container
  613.         _fContainerHandle = ODNewHandle(0);
  614.         _fContainer = CreateMemoryContainer(ev, _fSession, _fContainerHandle, kODBentoMemoryContainer);
  615.  
  616.         // Create the root content storage unit
  617.         _fDocument = _fContainer->AcquireDocument(ev, kODDefaultDocument);
  618.         _fDraft = _fDocument->AcquireBaseDraft(ev, kODDPExclusiveWrite);
  619.         _fSU = _fDraft->CreateStorageUnit(ev);
  620.  
  621.         // Store a reference to the content storage unit in the draft properties
  622.         draftProperties = _fDraft->AcquireDraftProperties(ev);
  623.         ODSetStrongSURefProp(ev, draftProperties, kODPropRootPartSU, kODStrongStorageUnitRef, _fSU->GetID(ev));    
  624.         draftProperties->Release(ev);
  625.  
  626.     CATCH_ALL
  627. #ifdef _REPORT_SCRAP_ERRORS_
  628.         WARN("ODClipboard: Cannot create clipboard - error %ld",ErrorCode());
  629. #endif
  630.         somSelf->DiscardClipboard(ev);
  631.         ODReleaseObject(ev, draftProperties);
  632.         RERAISE;
  633.     ENDTRY
  634.     
  635.     gODSuppressBentoFatalError = oldSuppress; // neutral
  636. }
  637.  
  638. //------------------------------------------------------------------------------
  639. // CloseClipboard
  640. //------------------------------------------------------------------------------
  641. // Close the current clipboard container, without disposing of the container handle.
  642. // Note: CloseClipboard must not make any method calls to somSelf, since
  643. //         CloseClipboard is called from the somUninit method.
  644.  
  645. ODStatic void CloseClipboard(ODClipboard *somSelf, Environment *ev, ODBoolean externalize)
  646. {
  647.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  648.  
  649.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  650.     gODSuppressBentoFatalError = kODTrue;
  651.     
  652.     // If the draft must be externalized, first externalize the root storage unit
  653.     // to resolve promises.  Otherwise, externalizing the draft may fail with an
  654.     // iterator-out-of-sync error because resolving promises may add storage units
  655.     // to the draft's collection during iteration.  In theory, the only promises
  656.     // should be in the root storage unit, so explicitly externalize it first to
  657.     // resolve promises before interating over all storage units.
  658.  
  659.     if ( _fSU != kODNULL )
  660.     {
  661.         if ( externalize )
  662.             _fSU->Externalize(ev);
  663.         else
  664.             _fSU->ClearAllPromises(ev);
  665.     }
  666.     
  667.     if ( (_fDraft != kODNULL) && externalize )
  668.     {
  669.         _fDraft->Externalize(ev);
  670.     }
  671.  
  672.     ODReleaseObject(ev,_fSU);
  673.     ODReleaseObject(ev,_fDraft);
  674.     ODReleaseObject(ev,_fDocument);
  675.     ODReleaseObject(ev,_fContainer);
  676.     
  677.     gODSuppressBentoFatalError = oldSuppress; // neutral
  678. }
  679.  
  680. //------------------------------------------------------------------------------
  681. // ODClipboard::DiscardClipboard
  682. //------------------------------------------------------------------------------
  683.  
  684. SOM_Scope void  SOMLINK ODClipboardDiscardClipboard(ODClipboard *somSelf, Environment *ev)
  685. {
  686.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  687.     ODClipboardMethodDebug("ODClipboard","DiscardClipboard");
  688.  
  689.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  690.     gODSuppressBentoFatalError = kODTrue;
  691.  
  692.     SOM_CATCH
  693.     {
  694.         gODSuppressBentoFatalError = oldSuppress; // neutral
  695.         return;
  696.     }
  697.     
  698.     CloseClipboard(somSelf, ev, kODFalse);
  699.     
  700.     ODDisposeHandle(_fContainerHandle);
  701.     _fContainerHandle = (ODHandle) kODNULL;
  702.     
  703.     gODSuppressBentoFatalError = oldSuppress; // neutral
  704. }
  705.  
  706. //------------------------------------------------------------------------------
  707. // ODClipboard::ImportContent
  708. //------------------------------------------------------------------------------
  709. //
  710. // On entry, assumes the scrap has already been checked for consistency.
  711. // Returns an exception if the scrap can't be loaded into memory.
  712.  
  713. SOM_Scope void  SOMLINK ODClipboardImportContent(ODClipboard *somSelf, Environment *ev)
  714. {
  715.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  716.     ODClipboardMethodDebug("ODClipboard","ImportContent");
  717.     
  718.     ODHandle    hData = kODNULL;
  719.     long        scrapOffset = 0;
  720.     
  721.     ODVolatile(hData);
  722.     
  723.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  724.     gODSuppressBentoFatalError = kODTrue;
  725.     
  726.     SOM_TRY
  727.     
  728.         hData = ODNewHandle(0);
  729.  
  730.         // Because we walk the scrap, it must be loaded in memory.
  731.         THROW_IF_ERROR(ClipboardLoadScrap());
  732.     
  733.         PScrapStuff myScrapStuff = InfoScrap();
  734.         Handle        hScrap = myScrapStuff->scrapHandle;
  735.  
  736.         while ( scrapOffset < myScrapStuff->scrapSize )
  737.         {
  738.             long        scrapTypeLength;
  739.             ResType        theType;
  740.             ODULong        realOffset;
  741.     
  742.             // There is more in the scrap
  743.             theType = *(ResTypePtr)(((long) *hScrap) + scrapOffset);
  744.             scrapTypeLength = GetScrap((Handle) hData, theType, (long*) &realOffset);
  745.             if ( scrapTypeLength < 0 )
  746.                 THROW(scrapTypeLength);
  747.  
  748.             if ( realOffset < scrapOffset )
  749.             {
  750.                 // We tried to read a second occurance of the same resource type
  751.                 // on the scrap.  Since the result of GetScrap is the length
  752.                 // of the first occurance, we can't read the scrap past this point.
  753.                 // So just quit.
  754. #ifdef _REPORT_SCRAP_ERRORS_
  755.                 PRINT("ODClipboard: ImportContent: Duplicate resource on scrap, type = \'%.4s\'\n", &theType);
  756. #endif
  757.                 break;
  758.             }
  759.  
  760. #if ODDebugClipboard
  761.             PRINT("Found scrap type \'%.4s\'\n", &theType);
  762. #endif
  763.             if ( scrapTypeLength > 0 )
  764.             {
  765. #ifdef _REPORT_SCRAP_ERRORS_
  766.                 if ( theType == kODScrapTypeODBentoContainer )
  767.                 {
  768.                     // Internal error
  769.                     WARN("ODClipboard: ImportContent: Reading BentoContainer as scrap type!");
  770.                 }
  771. #endif
  772.                 // Special case: If 'styl' is present, create an 'stxt' if one
  773.                 // isn't also on the scrap
  774.                 if ( theType == 'styl' )
  775.                 {
  776.                     long dummy;
  777.                     if ( GetScrap(nil, 'stxt', &dummy) == noTypeErr )
  778.                         ImportStyledTextType(somSelf, ev);
  779.                 }
  780.                 
  781.                 TempODType theISOType = kODNULL;
  782.                 theISOType = _fSession->GetTranslation(ev)->GetISOTypeFromPlatformType(ev, theType, kODPlatformDataType);
  783.         
  784.                 if ( theISOType != (ODType) kODNULL )
  785.                 {
  786.                     if ( ODSUExistsThenFocus(ev, _fSU, kODPropContents, (ODType) theISOType) )
  787.                     {
  788.                         WARN("ODClipboard: Replacing value on clipboard");
  789.                         _fSU->Remove(ev);
  790.                     }
  791.                     ODSUForceFocus(ev, _fSU, kODPropContents, (ODType) theISOType);
  792.                     ODValue pData = ODLockHandle(hData);
  793.                     StorageUnitSetValue(_fSU, ev, (ODULong) scrapTypeLength, pData);
  794.                     ODUnlockHandle(hData);
  795.                 }
  796.             }
  797.  
  798.             // The length must be EVEN!
  799.             if (scrapTypeLength & 1)
  800.             {
  801.                 scrapTypeLength += 1;
  802.             }
  803.             scrapOffset = realOffset + scrapTypeLength;
  804.         }
  805.  
  806.     SOM_CATCH_ALL
  807.  
  808. #ifdef _REPORT_SCRAP_ERRORS_
  809.         WARN("ODClipboard: ImportContent: Failed with error %ld",ErrorCode());
  810. #endif
  811.         if ( ErrorCode() == memFullErr )
  812.             SetErrorCode(kODErrOutOfMemory);
  813.  
  814.     SOM_ENDTRY
  815.  
  816.     gODSuppressBentoFatalError = oldSuppress; // neutral
  817.  
  818.     ODDisposeHandle(hData);
  819. }
  820.  
  821. //------------------------------------------------------------------------------
  822. // ODClipboard::PutContentOnPlatformClipboard
  823. //------------------------------------------------------------------------------
  824. //
  825. // Copy values with corresponding platform types onto the desk scrap.
  826. // THROWs an exception if any error occurs, which may cause the desk scrap to
  827. // be only partially updated. The desk scrap requires copying the data in one chunk.
  828.  
  829. SOM_Scope void  SOMLINK ODClipboardPutContentOnPlatformClipboard(ODClipboard *somSelf, Environment *ev)
  830. {
  831.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  832.     ODClipboardMethodDebug("ODClipboard","PutContentOnPlatformClipboard");
  833.     
  834.     ODULong            count;
  835.     ODULong            index;
  836.     ODPlatformType    platformType;
  837.  
  838.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  839.     gODSuppressBentoFatalError = kODTrue;
  840.  
  841.     SOM_TRY
  842.  
  843.         if ( (_fSU == kODNULL) && (_fContainerHandle != kODNULL) )
  844.             OpenClipboard(somSelf, ev);
  845.             
  846.         if ( _fSU )
  847.         {
  848.             _fSU->Focus(ev, kODPropContents, kODPosUndefined, 0, 0, kODPosUndefined);
  849.             count = _fSU->CountValues(ev);
  850.             for (index = 1; index <= count; ++index)
  851.             {
  852.                 _fSU->Focus(ev, kODPropContents, kODPosUndefined, 0, index, kODPosUndefined);
  853.                 TempODType theISOType = _fSU->GetType(ev);
  854.                 platformType = _fSession->GetTranslation(ev)->GetPlatformTypeFromISOType(ev, (ODType) theISOType);
  855.                 if (platformType != (ODPlatformType) kODNULL)
  856.                 {
  857.                     _fSU->Focus(ev, kODPropContents, kODPosUndefined, (ODType) theISOType, 0, kODPosUndefined);
  858.                     Size dataSize = _fSU->GetSize(ev);
  859.  
  860.                     TempODPtr data = kODNULL;
  861.                     data = ODNewPtr(dataSize, kDefaultHeapID);
  862.  
  863.                     StorageUnitGetValue(_fSU, ev, dataSize, (ODValue) data);
  864.     
  865.                     THROW_IF_ERROR(ClipboardPutScrap(dataSize, platformType, data));
  866.  
  867.                     // If styled text ('stxt') was just written to the scrap, also write
  868.                     // 'stly' if a 'TEXT' representation will also be written.
  869.                     if ( platformType == 'stxt' )
  870.                         if ( _fSU->Exists(ev, kODPropContents, kODAppleTEXT, 0) )
  871.                             if ( !_fSU->Exists(ev, kODPropContents, kODApplestyl, 0) )
  872.                                 THROW_IF_ERROR(ExportStylType(data));
  873.                 }
  874.             }
  875.         }
  876.  
  877.     SOM_CATCH_ALL
  878.  
  879.     SOM_ENDTRY
  880.     
  881.     gODSuppressBentoFatalError = oldSuppress; // neutral
  882. }
  883.  
  884. //------------------------------------------------------------------------------
  885. // ODClipboard::ExportPlatformTypes
  886. //------------------------------------------------------------------------------
  887. //
  888. // Export data of the argument platform types to the host clipboard.
  889. // Since only one ISO type corresponds directly to a platform type (no translation
  890. // is attempted), we just examine each value on the clipboard and check if
  891. // its platform equivalent is present in the argument set.
  892.  
  893.  
  894. SOM_Scope void  SOMLINK ODClipboardExportPlatformTypes(ODClipboard *somSelf, Environment *ev,
  895.     ODPlatformTypeList* typeList)
  896. {
  897.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  898.     ODClipboardMethodDebug("ODClipboard","ExportPlatformTypes");
  899.     
  900.     ODULong    countOfValues;
  901.     ODULong    index;
  902.     ODULong    countToExport;
  903.     
  904.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  905.     gODSuppressBentoFatalError = kODTrue;
  906.     
  907.     SOM_TRY
  908.  
  909.         if ( (_fSU == kODNULL) && (_fContainerHandle != kODNULL) )
  910.             OpenClipboard(somSelf, ev);
  911.             
  912.         if ( _fSU )
  913.         {
  914.             _fSU->Focus(ev, kODPropContents, kODPosUndefined, 0, 0, kODPosUndefined);
  915.             countOfValues = _fSU->CountValues(ev);
  916.             if (typeList != (ODPlatformTypeList*) kODNULL)
  917.                 countToExport = typeList->Count(ev);
  918.             else
  919.                 countToExport = countOfValues;
  920.             
  921.             for (index = 1; (index <= countOfValues) && (countToExport > 0); ++index)
  922.             {
  923.                 _fSU->Focus(ev, kODPropContents, kODPosUndefined, 0, index, kODPosUndefined);
  924.                 TempODType theISOType = _fSU->GetType(ev);
  925.             
  926.                 ODPlatformType platformType = 
  927.                     _fSession->GetTranslation(ev)->GetPlatformTypeFromISOType(ev, (ODType) theISOType);
  928.                 if ( platformType != (ODPlatformType) 0 )
  929.                 {
  930.                     if ((typeList == (ODPlatformTypeList*) kODNULL) || (typeList->Contains(ev, platformType)))
  931.                     {
  932.                         _fSU->Focus(ev, kODPropContents, kODPosUndefined, (ODType) theISOType, 0, kODPosUndefined);
  933.                         Size dataSize = _fSU->GetSize(ev);
  934.  
  935.                         TempODPtr data = kODNULL;
  936.                         data = ODNewPtr(dataSize, kDefaultHeapID);
  937.                 
  938.                         StorageUnitGetValue(_fSU, ev, dataSize, (ODValue) data);
  939.             
  940.                         THROW_IF_ERROR(ClipboardPutScrap(dataSize, platformType, data));
  941.     
  942.                         if (typeList != (ODPlatformTypeList*) kODNULL)
  943.                             typeList->Remove(ev, platformType);
  944.                         countToExport -= 1;
  945.                     }
  946.                 }
  947.             }
  948.         }
  949.  
  950.     SOM_CATCH_ALL
  951.     
  952.         if ( ErrorCode() == memFullErr )
  953.             SetErrorCode(kODErrOutOfMemory);
  954.  
  955.     SOM_ENDTRY
  956.     
  957.     gODSuppressBentoFatalError = oldSuppress; // neutral
  958. }
  959.  
  960. //------------------------------------------------------------------------------
  961. // OpenClipboard
  962. //------------------------------------------------------------------------------
  963.  
  964. ODStatic void OpenClipboard(ODClipboard *somSelf, Environment *ev)
  965. {
  966.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  967.  
  968.     ODStorageUnitID    suID;
  969.     
  970.     ODVolatile(somSelf);
  971.     ODVolatile(ev);
  972.  
  973.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  974.     gODSuppressBentoFatalError = kODTrue;
  975.  
  976.     if ( _fContainerHandle )
  977.     {
  978.         TRY
  979.             _fContainer = GetMemoryContainer(ev, _fSession, _fContainerHandle, kODBentoMemoryContainer);        
  980.             _fDocument = _fContainer->AcquireDocument(ev, kODDefaultDocument);
  981.             _fDraft = _fDocument->AcquireBaseDraft(ev, kODDPExclusiveWrite);
  982.     
  983.             { TempODStorageUnit draftProperties = _fDraft->AcquireDraftProperties(ev);
  984.               suID = ODGetStrongSURefProp(ev, draftProperties, kODPropRootPartSU, kODStrongStorageUnitRef);
  985.             }
  986.     
  987.             _fSU = _fDraft->AcquireStorageUnit(ev, suID);
  988.         CATCH_ALL
  989.             CloseClipboard(somSelf, ev, kODFalse);
  990.             RERAISE;
  991.         ENDTRY
  992.     }
  993.     
  994.     gODSuppressBentoFatalError = oldSuppress; // neutral
  995. }
  996.  
  997. //------------------------------------------------------------------------------
  998. // ODClipboard::PutClipboardOnPlatformClipboard
  999. //------------------------------------------------------------------------------
  1000. //
  1001. // This method has the side effect of closing the clipboard container.
  1002. // Also note that by externalizing the clipboard draft, all promises are resolved.
  1003.  
  1004. SOM_Scope void  SOMLINK ODClipboardPutClipboardOnPlatformClipboard(ODClipboard *somSelf, Environment *ev)
  1005. {
  1006.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1007.     ODClipboardMethodDebug("ODClipboard","PutClipboardOnPlatformClipboard");
  1008.     
  1009.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  1010.     gODSuppressBentoFatalError = kODTrue;
  1011.     
  1012.     SOM_TRY 
  1013.  
  1014.     // Externalize then close the clipboard container
  1015.     CloseClipboard(somSelf, ev, kODTrue);
  1016.  
  1017.     if ( _fContainerHandle )
  1018.     {
  1019.         OSErr    error;
  1020.         Size    dataSize;
  1021.         char    flags;
  1022.     
  1023.         dataSize = ODGetHandleSize(_fContainerHandle);
  1024.  
  1025.         THROW_IF_ERROR(UnloadScrapIfMemLow(dataSize));
  1026.  
  1027.         flags = HGetState((Handle) _fContainerHandle);
  1028.         Ptr containerPtr = (Ptr) ODLockHandle(_fContainerHandle);
  1029.         error = (OSErr) PutScrap(dataSize, kODScrapTypeODBentoContainer, containerPtr);
  1030.         HSetState((Handle) _fContainerHandle, flags);
  1031.  
  1032. #ifdef _REPORT_SCRAP_ERRORS_
  1033.         WASSERTM(error == noErr, "ODClipboard: PutScrap() failed");
  1034. #endif
  1035.         THROW_IF_ERROR(error);
  1036.     }
  1037. #ifdef _REPORT_SCRAP_ERRORS_
  1038.     else
  1039.     {
  1040.         // Internal error
  1041.         WARN("ODClipboard: PutClipboardOnPlatformClipboard: No Clipboard to export!\n");
  1042.     }
  1043. #endif
  1044.  
  1045.     SOM_CATCH_ALL
  1046.     
  1047. #ifdef _REPORT_SCRAP_ERRORS_
  1048.         WARN("ODClipboard: PutClipboardOnPlatformClipboard: Raising exception %d\n", ErrorCode());
  1049. #endif
  1050.  
  1051.     SOM_ENDTRY
  1052.     
  1053.     gODSuppressBentoFatalError = oldSuppress; // neutral
  1054. }
  1055.  
  1056. //------------------------------------------------------------------------------
  1057. // ODClipboard::ImportClipboard
  1058. //------------------------------------------------------------------------------
  1059. //
  1060. // A bento memory container is always used for data interchange.
  1061. // If OpenClipboard throws, its probably because a bad resource of type
  1062. // kODScrapTypeODBentoContainer was found on the clipboard (currently error 1012,
  1063. // but it may change and there may be others).
  1064. // This routine returns:
  1065. //        kODFalse, if the platform clipboard does not contain an OpenDoc clipboard;
  1066. //        kODTrue, if an OpenDoc clipboard is successfully imported;
  1067. //        an exception if an OpenDoc clipboard could not be imported
  1068.  
  1069. SOM_Scope ODBoolean  SOMLINK ODClipboardImportClipboard(ODClipboard *somSelf, Environment *ev)
  1070.     {
  1071.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1072.     ODClipboardMethodDebug("ODClipboard","ImportClipboard");
  1073.  
  1074.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  1075.     gODSuppressBentoFatalError = kODTrue;
  1076.  
  1077.     SOM_CATCH
  1078.     {
  1079.         gODSuppressBentoFatalError = oldSuppress; // neutral
  1080.         return kODFalse;
  1081.     }
  1082.     
  1083.     ODHandle    hData = kODNULL;
  1084.     Size        dataSize;
  1085.     long        dummy;
  1086.     
  1087.     WASSERTM(_fContainerHandle == (ODHandle) kODNULL, "ODClipboard: fContainerHandle not null");
  1088.     WASSERTM(_fContainer == (ODContainer*) kODNULL, "ODClipboard: fContainer not null");
  1089.     WASSERTM(_fDocument == (ODDocument*) kODNULL, "ODClipboard: fDocument not null");
  1090.     WASSERTM(_fDraft == (ODDraft*) kODNULL, "ODClipboard: fDraft not null");
  1091.     WASSERTM(_fSU == (ODStorageUnit*) kODNULL, "ODClipboard: fSU not null");
  1092.     
  1093.     if ( !ScrapHasType(kODScrapTypeODBentoContainer) )
  1094.         return kODFalse;
  1095.     
  1096.     ODVolatile(hData);
  1097.     
  1098.     TRY
  1099.         hData = ODNewHandle(0);
  1100.     
  1101.         dataSize = GetScrap((Handle) hData, kODScrapTypeODBentoContainer, &dummy);
  1102.         if ( dataSize < 0 )
  1103.         {
  1104.             if ( dataSize == memFullErr )
  1105.                 THROW(kODErrOutOfMemory);
  1106.             else
  1107.                 THROW(dataSize);
  1108.         }
  1109.     
  1110.         _fContainerHandle = hData;
  1111.  
  1112.         OpenClipboard(somSelf, ev);
  1113.     CATCH_ALL
  1114. #ifdef _REPORT_SCRAP_ERRORS_
  1115.         WARN("ODClipboard: Cannot import clipboard - error %ld",ErrorCode());
  1116. #endif
  1117.         _fContainerHandle = kODNULL;
  1118.         ODDisposeHandle(hData);
  1119.         RERAISE;
  1120.     ENDTRY
  1121.     
  1122.     gODSuppressBentoFatalError = oldSuppress; // neutral
  1123.     
  1124.     return kODTrue;
  1125. }
  1126.  
  1127. //------------------------------------------------------------------------------
  1128. // ODClipboard::GetUpdateID
  1129. //------------------------------------------------------------------------------
  1130.  
  1131. SOM_Scope ODUpdateID  SOMLINK ODClipboardGetUpdateID(ODClipboard *somSelf, Environment *ev)
  1132. {
  1133.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1134.     ODClipboardMethodDebug("ODClipboard","GetUpdateID");
  1135.     
  1136.     short curScrapCount = GetMacScrapCount();
  1137.     
  1138.     // If the desk scrap has not changed since we last imported it, 
  1139.     // or if the desk scrap has not changed since the last change to this clipboard,
  1140.     // return the current change id, otherwise, return the next change id.
  1141.     // Note that this routine will return the same "next" change id
  1142.     // even if the desk scrap has changed since the last call to this routine.
  1143.     if (curScrapCount == _fScrapCount)
  1144.         return _fUpdateID;
  1145.     else if (curScrapCount == _fScrapCountLastChange)
  1146.         return _fUpdateID;
  1147.     else
  1148.         return _fNextUpdateID;
  1149. }
  1150.  
  1151. //------------------------------------------------------------------------------
  1152. // ODClipboard::Clear
  1153. //------------------------------------------------------------------------------
  1154.  
  1155. SOM_Scope void  SOMLINK ODClipboardClear(ODClipboard *somSelf, Environment *ev)
  1156. {
  1157.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1158.     ODClipboardMethodDebug("ODClipboard","Clear");
  1159.  
  1160. #if ODDebugClipboard
  1161.     PRINT("ODClipboard::Clear \n");
  1162. #endif
  1163.     
  1164.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  1165.     gODSuppressBentoFatalError = kODTrue;
  1166.     
  1167.     if ( !IsFrontProcess() )
  1168.     {
  1169.         ODSetSOMException(ev, kODErrBackgroundClipboardClear);
  1170.         return;
  1171.     }
  1172.     
  1173.     // Unless called when the process is in the background,
  1174.     // don't return an error so this method can be called in a failure handler.
  1175.     FN_CATCH
  1176.     {    
  1177.         gODSuppressBentoFatalError = oldSuppress; // neutral
  1178.         return; 
  1179.     }
  1180.  
  1181. #if ODDebugClipboard
  1182.     if ( (_fSU != (ODStorageUnit*) kODNULL) && (_fSU->GetRefCount(ev) != 1) )
  1183.         PRINT("ODClipboard::Clear - Storage unit refCount = %d\n", _fSU->GetRefCount(ev));
  1184. #endif
  1185.     
  1186.     somSelf->DiscardClipboard(ev);
  1187.     
  1188.     _fUpdateID = _fNextUpdateID;
  1189.     _fNextUpdateID = _fSession->UniqueUpdateID(ev);
  1190.  
  1191. #if ODDebugClipboard
  1192.     PRINT("ODClipboard::Clear _fOriginalDraft = kODNULL\n");
  1193. #endif
  1194.     
  1195.     _fOriginalDraft = kODNULL;
  1196.     _fOriginalCloneKind = kODCloneCopy;
  1197.     _fClonePasteCount = 0;
  1198.     
  1199.     // Remember to export to desk scrap
  1200.     _fScrapCountLastChange = _fScrapCount = GetMacScrapCount();
  1201.     
  1202.     gODSuppressBentoFatalError = oldSuppress; // neutral
  1203. }
  1204.  
  1205. //------------------------------------------------------------------------------
  1206. // ODClipboard::GetContentStorageUnit
  1207. //------------------------------------------------------------------------------
  1208. //
  1209. // If importing from the host clipboard fails, this method returns a new, empty
  1210. // storage unit.  No alert is displayed to inform the user.  This method will
  1211. // retry importing until Clear() is called.  An exception is returned only if
  1212. // an empty clipboard cannot be created.
  1213. //
  1214. // If this routine is called when the process is in the background, GetScrap()
  1215. // will probably return memFullError.  Even if it did return scrap data, the
  1216. // data would not be reliable because the forground application might be keeping
  1217. // the true clipboard data in a private scrap.  So rather than returning a scrap
  1218. // error, just return an empty clipboard.
  1219.  
  1220. SOM_Scope ODStorageUnit*  SOMLINK ODClipboardGetContentStorageUnit(ODClipboard *somSelf, Environment *ev)
  1221. {
  1222.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1223.     ODClipboardMethodDebug("ODClipboard","GetContentStorageUnit");
  1224.     
  1225.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  1226.     gODSuppressBentoFatalError = kODTrue;
  1227.  
  1228.     SOM_CATCH
  1229.     {
  1230.         gODSuppressBentoFatalError = oldSuppress; // neutral
  1231. #ifdef _REPORT_SCRAP_ERRORS_
  1232.         WARN("ODClipboard: GetContentStorageUnit: Raising exception %d\n", ErrorCode());
  1233. #endif
  1234.         return kODNULL;
  1235.     }
  1236.     
  1237.     ODVolatile(somSelf);
  1238.     ODVolatile(ev);
  1239.  
  1240.     short curScrapCount = GetMacScrapCount();
  1241.     
  1242. #if ODDebugClipboard
  1243.     if ( (_fSU != (ODStorageUnit*) kODNULL) && (_fSU->GetRefCount(ev) != 1) )
  1244.         PRINT("ODClipboard::GetContentStorageUnit - Storage unit refCount = %d\n", _fSU->GetRefCount(ev));
  1245. #endif
  1246.  
  1247.     // _fScrapCount is the platform scrap count that was last imported or in effect when the clipboard changed.
  1248.     // If "curScrapCount == _fScrapCount", the platform scrap has not changed since it was last imported.
  1249.     // _fScrapCountLastChange is the platform scrap count at the time the OpenDoc clipboard last changed.
  1250.     // If "curScrapCount == _fScrapCountLastChange", the platform scrap has not changed since the
  1251.     // OpenDoc clipboard last changed.
  1252.  
  1253.     if ( (curScrapCount != _fScrapCount) && (curScrapCount != _fScrapCountLastChange) )
  1254.     {
  1255.         // Import from desk scrap into the OpenDoc clipboard
  1256. #if ODDebugClipboard
  1257.         PRINT("ODClipboard: GetContentStorageUnit: Updating clipboard from scrap\n");
  1258. #endif
  1259.  
  1260.         somSelf->DiscardClipboard(ev);
  1261.  
  1262.         TRY
  1263.             if ( ScrapHasData() )
  1264.             {
  1265.                 if ( !somSelf->ImportClipboard(ev) )
  1266.                 {
  1267.                     somSelf->NewClipboard(ev);
  1268.                     somSelf->ImportContent(ev);
  1269.                 }
  1270.             }
  1271.             else
  1272.             {
  1273.                 somSelf->NewClipboard(ev);
  1274.             }
  1275.             _fScrapCount = curScrapCount;
  1276.             _fUpdateID = _fNextUpdateID;
  1277.             _fNextUpdateID = _fSession->UniqueUpdateID(ev);
  1278.         CATCH_ALL
  1279. #ifdef _REPORT_SCRAP_ERRORS_
  1280.             if ( IsFrontProcess() )
  1281.                 WARN("ODClipboard: GetContentStorageUnit: Importing from desk scrap raised exception %d\n", ErrorCode());
  1282. #endif
  1283.             // Importing an OpenDoc clipboard, content, or NewClibpard failed;
  1284.             // just create a new, empty clipboard
  1285.             somSelf->DiscardClipboard(ev);
  1286.             somSelf->NewClipboard(ev);
  1287.         ENDTRY
  1288.         _fOriginalDraft = kODNULL;
  1289.         _fOriginalCloneKind = kODCloneCopy;
  1290.         _fClonePasteCount = 0;
  1291.     }
  1292.     else if ( _fContainerHandle == (ODHandle) kODNULL )
  1293.     {
  1294.         // Open a new clipboard container if a container handle doesn't exist
  1295.         // This case can only happen after an error or after Clear() is called
  1296.         somSelf->NewClipboard(ev);
  1297.         _fOriginalDraft = kODNULL;
  1298.         _fOriginalCloneKind = kODCloneCopy;
  1299.         _fClonePasteCount = 0;
  1300.     }
  1301.     else
  1302.     {
  1303.         // reopen the container handle if necessary.
  1304.         if ( _fContainer == kODNULL )
  1305.             OpenClipboard(somSelf, ev);
  1306.         if ( _fOriginalDraft == kODNULL )
  1307.             _fOriginalDraft = GetOriginalDraft(ev, _fDraft);
  1308.     }
  1309.  
  1310.     gODSuppressBentoFatalError = oldSuppress; // neutral
  1311.  
  1312.     return _fSU;
  1313. }
  1314.  
  1315. //------------------------------------------------------------------------------
  1316. // ODClipboard::ActionDone
  1317. //------------------------------------------------------------------------------
  1318.  
  1319. SOM_Scope ODUpdateID  SOMLINK ODClipboardActionDone(ODClipboard *somSelf, Environment *ev,
  1320.     ODCloneKind cloneKind)
  1321. {
  1322.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1323.     ODClipboardMethodDebug("ODClipboard","ActionDone");
  1324.  
  1325.     ODUpdateID update = kODUnknownUpdate;
  1326.     
  1327.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  1328.     gODSuppressBentoFatalError = kODTrue;
  1329.     
  1330.     SOM_TRY
  1331.  
  1332.         // Note that if the clipboard is changed by one OpenDoc document,
  1333.         // and used (via Paste) in another, the sequence of undo, redo, 
  1334.         // and paste actions is separate in each document. That is, the
  1335.         // first document is unaware of the Paste in the second document.
  1336.         // This isn't semantically correct, but doesn't cause errors [cc].
  1337.  
  1338.         if ( (cloneKind == kODCloneCut) || (cloneKind == kODCloneCopy) )
  1339.         {
  1340.             _fOriginalCloneKind = cloneKind;
  1341.             _fClonePasteCount = 0;
  1342.         }
  1343.         else if ( cloneKind == kODClonePaste )
  1344.         {
  1345.             _fClonePasteCount += 1;
  1346.         }
  1347.         else
  1348.             THROW(kODErrIllegalClipboardCloneKind);
  1349.  
  1350.         update = _fUpdateID;
  1351.     
  1352.     SOM_CATCH_ALL
  1353.     
  1354.     SOM_ENDTRY
  1355.     
  1356.     gODSuppressBentoFatalError = oldSuppress; // neutral
  1357.     
  1358.     return update;
  1359. }
  1360.  
  1361. //------------------------------------------------------------------------------
  1362. // ODClipboard::ActionUndone
  1363. //------------------------------------------------------------------------------
  1364.  
  1365. SOM_Scope void  SOMLINK ODClipboardActionUndone(ODClipboard *somSelf, Environment *ev,
  1366.     ODUpdateID update,
  1367.     ODCloneKind originalCloneKind)
  1368. {
  1369.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1370.     ODClipboardMethodDebug("ODClipboard","ActionUndone");
  1371.  
  1372.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  1373.     gODSuppressBentoFatalError = kODTrue;
  1374.  
  1375.     SOM_TRY
  1376.  
  1377.         if ( update == _fUpdateID )
  1378.         {
  1379.             if ( originalCloneKind == kODCloneCut )
  1380.             {
  1381.                 SetOriginalCloneKind(ev, _fDraft, kODCloneCopy);
  1382.             }
  1383.             else if ( originalCloneKind == kODClonePaste )
  1384.             {
  1385.                 _fClonePasteCount -= 1;
  1386.                 if ( (_fClonePasteCount == 0) && (_fOriginalCloneKind == kODCloneCut) )
  1387.                     SetOriginalCloneKind(ev, _fDraft, kODCloneCut);
  1388.             }
  1389.             else if ( originalCloneKind != kODCloneCopy )
  1390.                 THROW(kODErrIllegalClipboardCloneKind);
  1391.         }
  1392.  
  1393.     SOM_CATCH_ALL
  1394.     
  1395.     SOM_ENDTRY
  1396.     
  1397.     gODSuppressBentoFatalError = oldSuppress; // neutral
  1398. }
  1399.  
  1400. //------------------------------------------------------------------------------
  1401. // ODClipboard::ActionRedone
  1402. //------------------------------------------------------------------------------
  1403.  
  1404. SOM_Scope void  SOMLINK ODClipboardActionRedone(ODClipboard *somSelf, Environment *ev,
  1405.     ODUpdateID update,
  1406.     ODCloneKind originalCloneKind)
  1407. {
  1408.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1409.     ODClipboardMethodDebug("ODClipboard","ActionRedone");
  1410.  
  1411.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  1412.     gODSuppressBentoFatalError = kODTrue;
  1413.  
  1414.     SOM_TRY
  1415.  
  1416.         if ( update == _fUpdateID )
  1417.         {
  1418.             if ( originalCloneKind == kODCloneCut )
  1419.             {
  1420.                 SetOriginalCloneKind(ev, _fDraft, kODCloneCut);
  1421.             }
  1422.             else if ( originalCloneKind == kODClonePaste )
  1423.             {
  1424.                 _fClonePasteCount += 1;
  1425.                 if ( (_fClonePasteCount == 1) )
  1426.                     SetOriginalCloneKind(ev, _fDraft, kODCloneCopy);
  1427.             }
  1428.             else if ( originalCloneKind != kODCloneCopy )
  1429.                 THROW(kODErrIllegalClipboardCloneKind);
  1430.         }
  1431.  
  1432.     SOM_CATCH_ALL
  1433.     
  1434.     SOM_ENDTRY
  1435.     
  1436.     gODSuppressBentoFatalError = oldSuppress; // neutral
  1437. }
  1438.  
  1439. //------------------------------------------------------------------------------
  1440. // ODClipboard::SetPlatformClipboard
  1441. //------------------------------------------------------------------------------
  1442.  
  1443. SOM_Scope void  SOMLINK ODClipboardSetPlatformClipboard(ODClipboard *somSelf, Environment *ev,
  1444.     ODPlatformTypeList* typeList)
  1445. {
  1446.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1447.     ODClipboardMethodDebug("ODClipboard","SetPlatformClipboard");
  1448.     
  1449.     ODPlatformTypeList* requestedTypes = (ODPlatformTypeList*) kODNULL;
  1450.     ODVolatile(requestedTypes);
  1451.     
  1452.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  1453.     gODSuppressBentoFatalError = kODTrue;
  1454.     
  1455.     short scrapCount = GetMacScrapCount();
  1456.  
  1457.     if ( (scrapCount == _fScrapCountLastChange) && (scrapCount == _fScrapCount) )
  1458.     {
  1459.         SOM_TRY
  1460.         
  1461.             THROW_IF_ERROR(ForceZeroScrap());
  1462.  
  1463.             if ( _fSU != (ODStorageUnit*) kODNULL )
  1464.             {
  1465.                 if ( typeList )
  1466.                     requestedTypes = _fSession->GetStorageSystem(ev)->CreatePlatformTypeList(ev, typeList);
  1467.  
  1468.                 TRY
  1469.                     somSelf->ExportPlatformTypes(ev, requestedTypes);
  1470.                 CATCH_ALL
  1471.                     ZeroScrap();
  1472.                     RERAISE;
  1473.                 ENDTRY
  1474.             }
  1475.  
  1476.         SOM_CATCH_ALL
  1477.         
  1478.         SOM_ENDTRY
  1479.  
  1480.         if ( requestedTypes )
  1481.             delete requestedTypes;
  1482.  
  1483.         // Since the scrap has only been partially updated, or an error has
  1484.         // occurred, we still need to remember to transfer everything later [cc]
  1485.         _fScrapCountLastChange = _fScrapCount = GetMacScrapCount();
  1486.     }
  1487.     
  1488.     gODSuppressBentoFatalError = oldSuppress; // neutral
  1489. }
  1490.  
  1491. //------------------------------------------------------------------------------
  1492. // ODClipboard::ExportClipboard
  1493. //------------------------------------------------------------------------------
  1494. //
  1495. // Returns a SOM exception if setting the platform clipboard fails.
  1496. // Unfortunately, until the clipboard container is closed its size isn't known.
  1497.  
  1498. SOM_Scope void  SOMLINK ODClipboardExportClipboard(ODClipboard *somSelf, Environment *ev)
  1499. {
  1500.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1501.     ODClipboardMethodDebug("ODClipboard","ExportClipboard");
  1502.     
  1503.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  1504.     gODSuppressBentoFatalError = kODTrue;
  1505.     
  1506.     SOM_TRY 
  1507.     
  1508.         // If this clipboard was the last change to the platform scrap ("count == _fScrapCountLastChange"),
  1509.         // and this clipboard has not already been copied to the platform scrap
  1510.         // ("count == _fScrapCount"), update the platform scrap now. [cc]
  1511.         
  1512.         short count = GetMacScrapCount();
  1513.         
  1514. #if ODDebugClipboard
  1515.         PRINT("ODClipboard::ExportClipboard called\n");
  1516.         if (count == _fScrapCountLastChange)
  1517.         {
  1518.             PRINT("ExportClipboard: OpenDoc clipboard contains last change\n");
  1519.             if ( count == _fScrapCount )
  1520.             {
  1521.                 PRINT("ExportClipboard: OpenDoc clipboard needs exporting");
  1522.                 if ( _fSU && _fSU->Exists(ev, kODPropLinkSpec, kODNULL, 0) )
  1523.                     PRINT(" (has link spec)");
  1524.                 PRINT("\n");
  1525.             }
  1526.             else if ( _fExportedLinkSpec && _fSU && !_fSU->Exists(ev, kODPropLinkSpec, kODNULL, 0) )
  1527.                 PRINT("ExportClipboard: OpenDoc clipboard needs exporting to remove link spec\n");
  1528.             else
  1529.                 PRINT("ExportClipboard: OpenDoc clipboard already copied to platform scrap\n");
  1530.         }
  1531. #endif
  1532.     
  1533.         ODBoolean needToExport = kODFalse;
  1534.         ODBoolean needToExportToRemoveLinkSpec = kODFalse;
  1535.         if  (count == _fScrapCountLastChange )
  1536.         {
  1537.             if ( count == _fScrapCount )
  1538.             {
  1539.                 needToExport = kODTrue;
  1540.                 _fExportedLinkSpec = _fSU && _fSU->Exists(ev, kODPropLinkSpec, kODNULL, 0);
  1541.             }
  1542.             else if ( _fExportedLinkSpec )
  1543.             {
  1544.                 needToExportToRemoveLinkSpec = _fSU && !_fSU->Exists(ev, kODPropLinkSpec, kODNULL, 0);
  1545.             }
  1546.         }
  1547.     
  1548.         // Immediately after changing the clipboard, _fOriginalDraft won't be set correctly
  1549.         // because the clipboard is not informed when a part is finished writing. [cc]
  1550.         if ( needToExport && (_fOriginalDraft == kODNULL) )
  1551.         {
  1552.             ASSERT(_fDraft != kODNULL, kODErrAssertionFailed);
  1553.             _fOriginalDraft = GetOriginalDraft(ev, _fDraft);
  1554.             WASSERTM(_fOriginalDraft != kODNULL, "Last clipboard change did not clone");
  1555.         }
  1556.     
  1557.         if ( needToExport || needToExportToRemoveLinkSpec )
  1558.         {
  1559.             // Copy the OpenDoc clipboard to the scrap
  1560.             THROW_IF_ERROR(ForceZeroScrap());
  1561.     
  1562.             // Optimistically load the scrap into memory if it was unloaded
  1563.             LoadScrap();
  1564.     
  1565.             TRY
  1566.                 somSelf->PutContentOnPlatformClipboard(ev);
  1567.                 somSelf->PutClipboardOnPlatformClipboard(ev);
  1568.                 
  1569.                 _fScrapCountLastChange = GetMacScrapCount();
  1570.             CATCH_ALL
  1571.                 // If writing the scrap fails, remove any scrap types written [cc]
  1572.                 ZeroScrap();
  1573. #ifdef _REPORT_SCRAP_ERRORS_
  1574.                 PRINT("ODClipboard::ExportClipboard failed; clearing scrap\n");
  1575. #endif
  1576.                 RERAISE;
  1577.             ENDTRY
  1578.  
  1579. #if ODDebugClipboard
  1580.             PRINT("ODClipboard::ExportClipboard updated the scrap, size is %ld\n", InfoScrap()->scrapSize);
  1581. #endif
  1582.         }
  1583.     
  1584.         // Exporting was successful
  1585.         if ( needToExportToRemoveLinkSpec )
  1586.             _fExportedLinkSpec = kODFalse;
  1587.  
  1588.     SOM_CATCH_ALL
  1589.  
  1590.         // If we fail to update the scrap for any reason, ensure fScrapCountLastChanged
  1591.         // and fScrapCount equals the Mac scrap count, so we can try again later if 
  1592.         // no other cut or copy is attempted.
  1593.         _fScrapCountLastChange = _fScrapCount = GetMacScrapCount();
  1594.  
  1595. #if ODDebugClipboard
  1596.         PRINT("ODClipboard::ExportClipboard failed!\n");
  1597. #endif
  1598.  
  1599.     SOM_ENDTRY
  1600.     
  1601. #if ODDebugClipboard
  1602.     PRINT("ODClipboard::ExportClipboard done, fExportedLinkSpec = %d\n", _fExportedLinkSpec);
  1603. #endif
  1604.  
  1605.     
  1606.     gODSuppressBentoFatalError = oldSuppress; // neutral
  1607. }
  1608.  
  1609. //------------------------------------------------------------------------------
  1610. // ODClipboard::DraftClosing
  1611. //------------------------------------------------------------------------------
  1612. //
  1613. // Forces resolution of promises, and prevents moving content across draft closings
  1614. // via the clipboard. In order to work correctly, parts MUST use BeginClone-EndClone
  1615. // when writing to the clipboard.
  1616.  
  1617. SOM_Scope void  SOMLINK ODClipboardDraftClosing(ODClipboard *somSelf, Environment *ev,
  1618.         ODDraft* draft)
  1619. {
  1620.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1621.     ODClipboardMethodDebug("ODClipboard","DraftClosing");
  1622.  
  1623. #if ODDebugClipboard
  1624.     PRINT("ODClipboard::DraftClosing called, draft is %x\n", draft);
  1625. #endif
  1626.  
  1627.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  1628.     gODSuppressBentoFatalError = kODTrue;
  1629.  
  1630.     SOM_CATCH
  1631.     {
  1632.         gODSuppressBentoFatalError = oldSuppress; // neutral
  1633.         return;
  1634.     }
  1635.  
  1636.     if ( draft )
  1637.     {
  1638.         // Immediately after changing the clipboard, _fOriginalDraft won't be set correctly
  1639.         // because the clipboard is not informed when a part is finished writing.
  1640.     
  1641.         short scrapCount = GetMacScrapCount();
  1642.         ODBoolean needToExport = (scrapCount == _fScrapCountLastChange) && (scrapCount == _fScrapCount);
  1643.         if ( needToExport && (_fOriginalDraft == kODNULL) )
  1644.         {
  1645.             ASSERT(_fDraft != kODNULL, kODErrAssertionFailed);
  1646.             _fOriginalDraft = GetOriginalDraft(ev, _fDraft);
  1647.             WASSERTM(_fOriginalDraft != kODNULL, "Last clipboard change did not clone");
  1648.         }
  1649.     
  1650. #if ODDebugClipboard
  1651.         PRINT("Last draft to change clipboard is %x\n", _fOriginalDraft);
  1652. #endif
  1653.  
  1654.         if ( _fOriginalDraft == draft )
  1655.         {
  1656.             // Last draft that wrote the clipboard is being closed.
  1657.  
  1658. #if ODDebugClipboard
  1659.             PRINT("ODClipboard::Draft that last wrote clipboard is closing\n", draft);
  1660.             if ( needToExport )
  1661.                 PRINT("ODClipboard::Clipboard needs exporting\n");
  1662. #endif
  1663.             // If the clipboard container is open, force resolution of promises 
  1664.             // by externalizing the clipboard draft. (If there are unresolved promises, 
  1665.             // the clipboard hasn't be exported yet). Otherwise open the container.
  1666.  
  1667.             if ( _fContainer )
  1668.                 _fDraft->Externalize(ev);
  1669.             else
  1670.                 OpenClipboard(somSelf, ev);
  1671.  
  1672.             // Remove a link spec if present
  1673.             ODSURemoveProperty(ev, _fSU, kODPropLinkSpec);
  1674.  
  1675.             // Check to see if content was cut (not copied) to the clipboard.
  1676.             // If so, change the original clone kind to copy, so any future
  1677.             // paste won't be treated as a move.
  1678.                         
  1679.             if ( GetOriginalCloneKind(ev, _fDraft) == kODCloneCut )
  1680.             {
  1681.                 SetOriginalCloneKind(ev, _fDraft, kODCloneCopy);
  1682.                 // Force exporting to platform clipboard
  1683.                 _fScrapCountLastChange = _fScrapCount = GetMacScrapCount();
  1684.             }
  1685.  
  1686.             _fOriginalDraft = kODNULL;
  1687.         }
  1688.     }
  1689.     
  1690.     gODSuppressBentoFatalError = oldSuppress; // neutral
  1691. }
  1692.  
  1693. //------------------------------------------------------------------------------
  1694. // ODClipboard::DraftSaved
  1695. //------------------------------------------------------------------------------
  1696. //
  1697.  
  1698. SOM_Scope void  SOMLINK ODClipboardDraftSaved(ODClipboard *somSelf, Environment *ev,
  1699.         ODDraft* draft)
  1700. {
  1701.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1702.     ODClipboardMethodDebug("ODClipboard","DraftSaved");
  1703.  
  1704. #if ODDebugClipboard
  1705.     PRINT("ODClipboard::DraftSaved called, draft %08x, orig %08x, fDraft %08x\n", 
  1706.         (long) draft, (long) _fOriginalDraft, (long) _fDraft);
  1707. #endif
  1708.  
  1709.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  1710.     gODSuppressBentoFatalError = kODTrue;
  1711.  
  1712.     SOM_CATCH
  1713.     {
  1714.         gODSuppressBentoFatalError = oldSuppress; // neutral
  1715.         return;
  1716.     }
  1717.     
  1718.     // ODDraft* tDraft = _fDraft;
  1719.     // ODDraft* tOriginalDraft = _fOriginalDraft;
  1720.     
  1721.     if ( draft )
  1722.     {
  1723.         if ( _fOriginalDraft == kODNULL )
  1724.         {
  1725.             if (_fDraft != kODNULL)        // can be null if never accessed
  1726.                 _fOriginalDraft = GetOriginalDraft(ev, _fDraft);
  1727.  
  1728. #if ODDebugClipboard
  1729.     PRINT("    ODClipboard::DraftSaved orig %08x\n", 
  1730.         (long) _fOriginalDraft);
  1731. #endif
  1732.         }
  1733.  
  1734.         if ( _fOriginalDraft == draft && _fDraft )
  1735.         {
  1736.             // Check to see if content was cut (not copied) to the clipboard.
  1737.             // If so, change the original clone kind to copy, so any future
  1738.             // paste won't be treated as a move.
  1739.  
  1740. #if ODDebugClipboard
  1741.             PRINT("        ODClipboard::DraftSaved try cut -> copy\n");
  1742. #endif
  1743.                         
  1744.             if ( GetOriginalCloneKind(ev, _fDraft) == kODCloneCut )
  1745.             {
  1746.                 SetOriginalCloneKind(ev, _fDraft, kODCloneCopy);
  1747.  
  1748. #if ODDebugClipboard
  1749.                 PRINT("            ODClipboard::DraftSaved perform cut -> copy\n");
  1750. #endif
  1751.             }
  1752.         }
  1753.     }
  1754.     
  1755.     gODSuppressBentoFatalError = oldSuppress; // neutral
  1756. }
  1757.  
  1758. //------------------------------------------------------------------------------
  1759. // ODClipboard::ShowPasteAsDialog
  1760. //------------------------------------------------------------------------------
  1761.  
  1762. SOM_Scope ODBoolean  SOMLINK ODClipboardShowPasteAsDialog(ODClipboard *somSelf, Environment *ev,
  1763.         ODBoolean canPasteLink,
  1764.         ODPasteAsMergeSetting mergeSetting,
  1765.         ODFacet* facet,
  1766.         ODTypeToken viewType,
  1767.         ODPasteAsResult* result)
  1768. {
  1769.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1770.     ODClipboardMethodDebug("ODClipboard","ShowPasteAsDialog");
  1771.  
  1772.     ODBoolean returnValue = kODFalse;
  1773.  
  1774.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  1775.     gODSuppressBentoFatalError = kODTrue;
  1776.  
  1777.     SOM_CATCH
  1778.     {
  1779.         gODSuppressBentoFatalError = oldSuppress; // neutral
  1780.         return kODFalse;
  1781.     }
  1782.  
  1783.     THROW_IF_NULL(facet, kODErrNullFacetInput);
  1784.     THROW_IF_NULL(result, kODErrNullPasteAsResultInput);
  1785.  
  1786.     ODTypeToken modalFocus = _fSession->Tokenize(ev, kODModalFocus);
  1787.     ODArbitrator* arbitrator = _fSession->GetArbitrator(ev);
  1788.     TempODFrame currentOwner = arbitrator->AcquireFocusOwner(ev, modalFocus);
  1789.  
  1790.     if ( arbitrator->RequestFocus(ev, modalFocus, facet->GetFrame(ev)) )
  1791.     {
  1792.         ODStorageUnit* clipContentSU = somSelf->GetContentStorageUnit(ev);
  1793.     
  1794.         ODBoolean isMove = (GetOriginalCloneKind(ev, clipContentSU->GetDraft(ev)) == kODCloneCut);
  1795.  
  1796.         returnValue = ShowPasteAsDialog(
  1797.                                 canPasteLink, 
  1798.                                 mergeSetting,
  1799.                                 isMove,
  1800.                                 clipContentSU,
  1801.                                 facet, 
  1802.                                 viewType, 
  1803.                                 result);
  1804.  
  1805.         arbitrator->TransferFocus(ev, modalFocus, facet->GetFrame(ev), currentOwner);
  1806.     }
  1807.     else
  1808.     {
  1809.         SysBeep(2);
  1810.     }
  1811.     
  1812.     gODSuppressBentoFatalError = oldSuppress; // neutral
  1813.  
  1814.     return returnValue;
  1815. }
  1816.  
  1817. //==============================================================================
  1818. // Local Functions
  1819. //==============================================================================
  1820.  
  1821. //------------------------------------------------------------------------------
  1822. // GetMacScrapCount
  1823. //------------------------------------------------------------------------------
  1824. //
  1825. // This function returns the identification stamp of the last mac scrap change,
  1826. // NOT the count of items on the scrap!
  1827.  
  1828. ODStatic short GetMacScrapCount()
  1829. {
  1830.     return InfoScrap()->scrapCount;
  1831. }
  1832.  
  1833. //------------------------------------------------------------------------------
  1834. // IsFrontProcess
  1835. //------------------------------------------------------------------------------
  1836.  
  1837. ODStatic ODBoolean IsFrontProcess()
  1838. {
  1839.     ProcessSerialNumber psnFront, psnMine;
  1840.     ODBoolean frontmost;
  1841.  
  1842.     GetFrontProcess(&psnFront);
  1843.     GetCurrentProcess(&psnMine);
  1844.     SameProcess(&psnFront, &psnMine, &frontmost);
  1845.  
  1846.     return frontmost;
  1847. }
  1848.  
  1849. //------------------------------------------------------------------------------
  1850. // ImportStyledTextType
  1851. //------------------------------------------------------------------------------
  1852.  
  1853. ODStatic void ImportStyledTextType(ODClipboard *somSelf, Environment *ev)
  1854. {
  1855.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1856.  
  1857.     ODHandle    hndl = kODNULL;
  1858.     ODValue        value;
  1859.     long        dummy;
  1860.  
  1861.     ODVolatile(hndl);
  1862.     ODVolatile(somSelf);
  1863.     ODVolatile(somThis);
  1864.     ODVolatile(ev);
  1865.  
  1866.     ODBoolean oldSuppress = gODSuppressBentoFatalError;
  1867.     gODSuppressBentoFatalError = kODTrue;
  1868.  
  1869.     SOM_CATCH
  1870.     {
  1871.         gODSuppressBentoFatalError = oldSuppress; // neutral
  1872.         if ( ODSUExistsThenFocus(ev, _fSU, kODPropContents, kODApplestxt) )
  1873.             _fSU->Remove(ev);
  1874.  
  1875.         ODDisposeHandle(hndl);
  1876.         return;
  1877.     }
  1878.     
  1879.     // Make sure both 'TEXT' and 'styl' are present
  1880.     ODULong sizeText = GetScrap(nil, 'TEXT', &dummy);
  1881.     ODULong sizeStyl = GetScrap(nil, 'styl', &dummy);
  1882.     
  1883.     if ( (sizeText < 0) || (sizeStyl < 0) )
  1884.         return;
  1885.  
  1886.     if ( ODSUExistsThenFocus(ev, _fSU, kODPropContents, kODApplestxt) )
  1887.     {
  1888. #ifdef _REPORT_SCRAP_ERRORS_
  1889.         WARN("ODClipboard: Replacing value on clipboard");
  1890. #endif
  1891.         _fSU->Remove(ev);
  1892.     }
  1893.     
  1894.     ODSUForceFocus(ev, _fSU, kODPropContents, kODApplestxt);
  1895.  
  1896.     hndl = ODNewHandle(sizeStyl);
  1897.     
  1898.     sizeStyl = GetScrap((Handle) hndl, 'styl', &dummy);
  1899.     if ( sizeStyl < 0 )
  1900.         THROW(sizeStyl);
  1901.  
  1902.     value = (ODValue) ODLockHandle(hndl);
  1903.     StorageUnitSetValue(_fSU, ev, sizeStyl, value);
  1904.     ODUnlockHandle(hndl);
  1905.     ODDisposeHandle(hndl);
  1906.     hndl = kODNULL;
  1907.  
  1908.     hndl = ODNewHandle(sizeText);
  1909.  
  1910.     sizeText = GetScrap((Handle) hndl, 'TEXT', &dummy);
  1911.     if ( sizeText < 0 )
  1912.         THROW(sizeText);
  1913.     
  1914.     value = (ODValue) ODLockHandle(hndl);
  1915.     StorageUnitSetValue(_fSU, ev, sizeText, value);
  1916.     ODUnlockHandle(hndl);
  1917.  
  1918.     ODDisposeHandle(hndl);
  1919.  
  1920.     gODSuppressBentoFatalError = oldSuppress; // neutral
  1921. }
  1922.  
  1923. //------------------------------------------------------------------------------
  1924. // ExportStylType
  1925. //------------------------------------------------------------------------------
  1926. //
  1927. // Argument is a pointer to styled text, with begins with a style record.
  1928.  
  1929. ODStatic OSErr ExportStylType(ODPtr    stxtData)
  1930. {
  1931.     Size stylSize = *((short *) stxtData);
  1932.     stylSize = (stylSize * sizeof(ScrpSTElement)) + sizeof(short);
  1933.     
  1934.     return ClipboardPutScrap(stylSize, 'styl', stxtData);
  1935. }
  1936.  
  1937. //------------------------------------------------------------------------------
  1938. // ScrapIsInconsistent
  1939. //------------------------------------------------------------------------------
  1940.  
  1941. ODStatic ODBoolean ScrapIsInconsistent()
  1942. {
  1943.     // Return false if the scrap in an inconsistent state and thus cannot
  1944.     // be read. [cc]
  1945.  
  1946. #if ODDebugClipboard
  1947.     if ( (InfoScrap()->scrapState > 0) && (InfoScrap()->scrapHandle == nil) )
  1948.         PRINT("ODClipboard: Scrap is inconsistent!\n");
  1949. #endif
  1950.  
  1951.     return  ((InfoScrap()->scrapState > 0) && (InfoScrap()->scrapHandle == nil));
  1952.     
  1953. }    
  1954.  
  1955. //------------------------------------------------------------------------------
  1956. // ScrapHasData
  1957. //------------------------------------------------------------------------------
  1958.  
  1959. ODStatic ODBoolean ScrapHasData()
  1960. {
  1961.     // Return true if the scrap size is greater than zero and the scrap is 
  1962.     // in a consistent state. [cc]
  1963.  
  1964.     return ((InfoScrap()->scrapSize > 0) && (!ScrapIsInconsistent()));
  1965. }    
  1966.  
  1967. //------------------------------------------------------------------------------
  1968. // ScrapHasType
  1969. //------------------------------------------------------------------------------
  1970.  
  1971. ODStatic ODBoolean ScrapHasType(ODPlatformType type)
  1972. {
  1973.     long        dummy;
  1974.     Size        dataSize;
  1975.     ODBoolean    result = kODFalse;
  1976.  
  1977.     if ( ScrapHasData() )
  1978.     {
  1979.         dataSize = GetScrap(nil, type, &dummy);
  1980.         if ( dataSize >= 0 )
  1981.             result = kODTrue;
  1982. #ifdef _REPORT_SCRAP_ERRORS_
  1983.         else
  1984.         {
  1985.             if (dataSize != noTypeErr )
  1986.                 WARN("ODClipboard: ScrapHasType: GetScrap() returned error %ld, type = %.4s", dataSize, &type);
  1987.         }
  1988. #endif
  1989.     }
  1990.     
  1991.     return result;
  1992. }
  1993.  
  1994. //------------------------------------------------------------------------------
  1995. // ForceZeroScrap
  1996. //------------------------------------------------------------------------------
  1997.  
  1998. ODStatic OSErr ForceZeroScrap()
  1999. {
  2000.     OSErr err = ZeroScrap();
  2001.     if ( err == nilHandleErr )
  2002.     {
  2003. #ifdef _REPORT_SCRAP_ERRORS_
  2004.         PRINT("ODClipboard: ZeroScrap returned error -109\n");
  2005. #endif
  2006.         // According to Dylan Ashe, if the scrap is inconsistent the best thing to
  2007.         // do is force re-initiaization of the scrap.  Use of this constant to
  2008.         // force re-initiaization will continue to work in Maxwell. [cc]
  2009.         InfoScrap()->scrapState = kUninitializedScrap;
  2010.         err = ZeroScrap();
  2011.     }
  2012.     return err;
  2013. }
  2014.  
  2015. //------------------------------------------------------------------------------
  2016. // ScrapMemoryAvailable
  2017. //------------------------------------------------------------------------------
  2018. //
  2019. // This function ensures than allocating dataSize bytes would still leave
  2020. // a 40K contiguous block free, as recommended by Inside Mac, Memory, 1-43. [cc]
  2021.  
  2022. ODStatic ODBoolean ScrapMemoryAvailable(Size dataSize)
  2023. {
  2024.     const Size kMemCushion = 40*1024;
  2025.     
  2026.     Size totalFree;
  2027.     Size contigFree;
  2028.     
  2029.     PurgeSpace(&totalFree, &contigFree);
  2030.     
  2031. #if ODDebugClipboard
  2032.     PRINT("Request %ld bytes with %ld available\n", dataSize, contigFree);
  2033. #endif
  2034.  
  2035.     return (dataSize + kMemCushion) < contigFree;
  2036. }
  2037.  
  2038. //------------------------------------------------------------------------------
  2039. // UnloadScrapIfMemLow
  2040. //------------------------------------------------------------------------------
  2041.  
  2042. ODStatic OSErr UnloadScrapIfMemLow(Size dataSize)
  2043. {
  2044.     OSErr unloadError = noErr;
  2045.     
  2046.     if ( InfoScrap()->scrapState != kScrapOnDisk )
  2047.     {
  2048.         if ( !ScrapMemoryAvailable(dataSize) )
  2049.         {
  2050.             unloadError = UnloadScrap();
  2051.     
  2052. #if ODDebugClipboard
  2053.             PRINT("ODClipboard: Scrap unloaded with error %d\n", unloadError);
  2054. #endif
  2055.         }
  2056.     }
  2057.  
  2058.     return unloadError;
  2059. }
  2060.  
  2061. //------------------------------------------------------------------------------
  2062. // ClipboardLoadScrap
  2063. //------------------------------------------------------------------------------
  2064.  
  2065. ODStatic OSErr ClipboardLoadScrap()
  2066. {
  2067.     OSErr loadError = noErr;
  2068.     
  2069.     if ( InfoScrap()->scrapState == kScrapOnDisk )
  2070.     {
  2071.         if ( ScrapMemoryAvailable(InfoScrap()->scrapSize) )
  2072.         {
  2073.             loadError = LoadScrap();
  2074.     
  2075. #if ODDebugClipboard
  2076.              PRINT("ODClipboard: Scrap loaded with error %d\n", loadError);
  2077. #endif
  2078.         }
  2079.         else
  2080.         {
  2081.             loadError = kODErrOutOfMemory;
  2082.         }
  2083.     }
  2084.  
  2085.     return loadError;
  2086. }
  2087.  
  2088. //------------------------------------------------------------------------------
  2089. // ClipboardPutScrap
  2090. //------------------------------------------------------------------------------
  2091.  
  2092. ODStatic OSErr ClipboardPutScrap(Size dataSize, ODPlatformType    platformType, ODPtr data)
  2093. {
  2094.     OSErr error = UnloadScrapIfMemLow(dataSize);
  2095.     
  2096.     if ( error == noErr )
  2097.     {
  2098.         error = (OSErr) PutScrap(dataSize, platformType, data);
  2099.  
  2100. #ifdef _REPORT_SCRAP_ERRORS_
  2101.         WASSERTM(error == noErr, "ODClipboard: PutScrap() failed");
  2102. #endif
  2103.     }
  2104.  
  2105.     return error;
  2106. }